package com.uziot.bucket.common.concurrent.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author shidt
 * @version V1.0
 * @className ThreadSafe2
 * @date 2021-05-13 14:34:36
 * @description <p/>
 * ReentrantLock 的测试
 * <p>
 * Condition 类和 Object 类锁方法区别区别
 * 1. Condition 类的 awiat 方法和 Object 类的 wait 方法等效
 * 2. Condition 类的 signal 方法和 Object 类的 notify 方法等效
 * 3. Condition 类的 signalAll 方法和 Object 类的 notifyAll 方法等效
 * 4. ReentrantLock 类可以唤醒指定条件的线程，而 object 的唤醒是随机的
 * tryLock 和 lock 和 lockInterruptibly 的区别
 * 1. tryLock 能获得锁就返回 true，不能就立即返回 false，tryLock(long timeout,TimeUnit
 * unit)，可以增加时间限制，如果超过该时间段还没获得锁，返回 false
 * 2. lock 能获得锁就返回 true，不能的话一直等待获得锁
 * 3. lock 和 lockInterruptibly，如果两个线程分别执行这两个方法，但此时中断这两个线程，
 * lock 不会抛出异常，而 lockInterruptibly 会抛出异常。
 */

@Slf4j
public class MyLockService {
    /**
     * 创建锁
     */
    private final Lock lock = new ReentrantLock();
    //公平锁
    //Lock lock=new ReentrantLock(true);
    //非公平锁
    //Lock lock=new ReentrantLock(false);
    /**
     * 创建 Condition
     */
    private final Condition condition = lock.newCondition();

    public void testMethod() {
        try {
            lock.lock();
            //1：wait 方法等待：
            //System.out.println("开始 wait");
            condition.await();
            //通过创建 Condition 对象来使线程 wait，必须先执行 lock.lock 方法获得锁
            //:2：signal 方法唤醒
            //condition 对象的 signal 方法可以唤醒 wait 线程
            condition.signal();
            for (int i = 0; i < 5; i++) {
                log.info("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}